#include "PCGSolver.h"
#include "PCGSolverTest.h"

float rand_float()
{
	return (rand() % 1000) / 1000.f;
}

void PCGSolverTest::test()
{
	/*
	PCGSolver* solver = new PCGSolver();

	unsigned numRows = 1000;

	float* vector = new float[numRows];
	int* neighborhood = new int[numRows*9];
	float* sparseMatrix = new float[numRows*9];
	float* solution = new float[numRows];

	for (unsigned row=0;row < numRows;row++)
	{
		vector[row] = rand_float();
		solution[row] = 0.f;
	}

	for (unsigned row=0; row < numRows; row++)
	{
		for (unsigned n=0; n<9; n++)
		{
			if (rand_float() < 0.5)
			{
				neighborhood[row*9+n] = -1;
			}
			else
			{
				unsigned neighbor = rand() % numRows;
				neighborhood[row*9+n] = neighbor;
				sparseMatrix[row*9+n] = rand_float();
				solution[row] += vector[neighbor] * sparseMatrix[row*9+n];
			}
		}
	}

	GLBuffer* vectorBuffer = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*numRows, vector, 0);
	GLBuffer* sparseMatrixBuffer = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*9*numRows, sparseMatrix, 0);
	GLBuffer* neighborhoodBuffer = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLint)*9*numRows, neighborhood, 0);
	GLBuffer* solutionBuffer = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*numRows, NULL, 0);

	solver->set(sparseMatrixBuffer, neighborhoodBuffer, NULL, numRows);
	solver->matrixTimesVector(vectorBuffer, solutionBuffer);

	glMemoryBarrier(GL_ALL_BARRIER_BITS);

	glBindBuffer(GL_SHADER_STORAGE_BUFFER, solutionBuffer->name);

	float* gpuSolution = new float[numRows];
	glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLfloat)*numRows, gpuSolution);
	float res=0.0;
	for (unsigned i=0;i<numRows;i++)
		res += (gpuSolution[i]-solution[i])*(gpuSolution[i]-solution[i]);
	printf("Residual = %f\n", res);

	delete vectorBuffer;
	delete sparseMatrixBuffer;
	delete neighborhoodBuffer;
	delete solutionBuffer;

	delete[] gpuSolution;
	delete[] solution;
	delete[] sparseMatrix;
	delete[] neighborhood;
	delete[] vector;


	delete solver;
	*/
}

void PCGSolverTest::test2()
{
	/*
	PCGSolver* solver = new PCGSolver();

	unsigned n=200000;

	float* v1 = new float[n];
	float* v2 = new float[n];
	float solution=0.f;

	for (unsigned i=0;i<n;i++)
	{
		v1[i] = rand_float()-0.5f;
		v2[i] = rand_float()-0.5f;
		solution += v1[i]*v2[i];
	}

	GLBuffer* v1Buffer = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*n, v1, 0);
	GLBuffer* v2Buffer = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*n, v2, 0);
	GLBuffer* solutionBuffer = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*3, NULL, 0);

	solver->scalarProduct(v1Buffer, v2Buffer, solutionBuffer, n);

	float gpuSolution;
	glBindBuffer(GL_SHADER_STORAGE_BUFFER, solutionBuffer->name);
	glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLfloat), &gpuSolution);

	printf("CPU: %f\nGPU: %f\n", solution, gpuSolution);

	delete v1Buffer;
	delete v2Buffer;

	delete[] v1;
	delete[] v2;
	*/
}

void PCGSolverTest::test3()
{
	/*
	PCGSolver* solver = new PCGSolver();

	unsigned n=6;

	GLfloat Adata[] = {
		7.8592,    1.2809,    0.1923,    1.1692,    1.0074,    0.6224, 0.0, 0.0, 0.0,
		7.3064,    1.2809,    0.8554,    1.3773,    1.4774,    1.7617, 0.0, 0.0, 0.0,
		6.5974,    0.1923,    0.8554,    1.2989,    1.8038,    1.7759, 0.0, 0.0, 0.0,
		7.4349,    1.1692,    1.3773,    1.2989,    1.1445,    0.3503, 0.0, 0.0, 0.0,
		7.5816,    1.0074,    1.4774,    1.8038,    1.1445,    0.6627, 0.0, 0.0, 0.0,
		7.0525,    0.6224,    1.7617,    1.7759,    0.3503,    0.6627, 0.0, 0.0, 0.0
	};

	GLint Ndata[] = {
		0,1,2,3,4,5,-1,-1,-1,
		1,0,2,3,4,5,-1,-1,-1,
		2,0,1,3,4,5,-1,-1,-1,
		3,0,1,2,4,5,-1,-1,-1,
		4,0,1,2,3,5,-1,-1,-1,
		5,0,1,2,3,4,-1,-1,-1,
	};

	GLfloat bData[] = {
		0.5964,
		0.0520,
		0.8951,
		0.7283,
		0.8184,
		0.5002
	};

	GLfloat xData[] = { 0.0,0.0,0.0,0.0,0.0,0.0 };
	
	GLBuffer* A = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*9*n, Adata, 0);
	GLBuffer* N = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(int)*9*n, Ndata, 0);
	GLBuffer* b = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*n, bData, 0);
	GLBuffer* x = GLBuffer::newImmutable(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*n, xData, 0);
	
	solver->set(A, N, b, n);
	solver->solve(x, 10);

	GLfloat* sol = new GLfloat[n];
	glBindBuffer(GL_SHADER_STORAGE_BUFFER, x->name);
	glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLfloat)*n, sol);
	for (unsigned i=0;i<n;i++)
		printf("%f\n", sol[i]);

	delete solver;
	*/
}